/*
mp3ç¼–ç å™¨ï¼Œéœ€å¸¦ä¸Šmp3-engine.jså¼•æ“Žä½¿ç”¨
https://github.com/xiangyuecn/Recorder

å½“ç„¶æœ€ä½³æŽ¨èä½¿ç”¨mp3ã€wavæ ¼å¼ï¼Œä»£ç ä¹Ÿæ˜¯ä¼˜å…ˆç…§é¡¾è¿™ä¸¤ç§æ ¼å¼
æµè§ˆå™¨æ”¯æŒæƒ…å†µ
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
*/
(function(){
"use strict";

Recorder.prototype.enc_mp3={
	stable:true
	,testmsg:"é‡‡æ ·çŽ‡èŒƒå›´48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000"
};



//*******æ ‡å‡†UIçº¿ç¨‹è½¬ç æ”¯æŒå‡½æ•°************

Recorder.prototype.mp3=function(res,True,False){
		var This=this,set=This.set,size=res.length;
		
		//ä¼˜å…ˆé‡‡ç”¨workerç¼–ç ï¼Œå¤ªä½Žç‰ˆæœ¬ä¸‹é¢ç”¨è€æ–¹æ³•æä¾›å…¼å®¹
		var ctx=This.mp3_start(set);
		if(ctx){
			This.mp3_encode(ctx,res);
			This.mp3_complete(ctx,True,False,1);
			return;
		};
		
		//https://github.com/wangpengfei15975/recorder.js
		//https://github.com/zhuker/lamejs bug:é‡‡æ ·çŽ‡å¿…é¡»å’Œæºä¸€è‡´ï¼Œä¸ç„¶8kæ—¶æ²¡æœ‰å£°éŸ³ï¼Œæœ‰é—®é¢˜fixï¼šhttps://github.com/zhuker/lamejs/pull/11
		var mp3=new Recorder.lamejs.Mp3Encoder(1,set.sampleRate,set.bitRate);
		
		var blockSize=57600;
		var data=[];
		
		var idx=0,mp3Size=0;
		var run=function(){
			if(idx<size){
				var buf=mp3.encodeBuffer(res.subarray(idx,idx+blockSize));
				if(buf.length>0){
					mp3Size+=buf.buffer.byteLength;
					data.push(buf.buffer);
				};
				idx+=blockSize;
				setTimeout(run);//å°½é‡é¿å…å¡ui
			}else{
				var buf=mp3.flush();
				if(buf.length>0){
					mp3Size+=buf.buffer.byteLength;
					data.push(buf.buffer);
				};
				
				//åŽ»æŽ‰å¼€å¤´çš„æ ‡è®°ä¿¡æ¯å¸§
				var meta=mp3TrimFix.fn(data,mp3Size,size,set.sampleRate);
				mp3TrimFixSetMeta(meta,set);
				
				True(new Blob(data,{type:"audio/mp3"}));
			};
		};
		run();
	}


//********è¾¹å½•è¾¹è½¬ç (Worker)æ”¯æŒå‡½æ•°ï¼Œå¦‚æžœæä¾›å°±ä»£è¡¨å¯èƒ½æ”¯æŒï¼Œå¦åˆ™åªæ”¯æŒæ ‡å‡†è½¬ç *********

//å…¨å±€å…±äº«ä¸€ä¸ªWorkerï¼ŒåŽå°ä¸²è¡Œæ‰§è¡Œã€‚å¦‚æžœæ¯æ¬¡éƒ½å¼€ä¸€ä¸ªæ–°çš„ï¼Œç¼–ç é€Ÿåº¦å¯èƒ½ä¼šæ…¢å¾ˆå¤šï¼Œå¯èƒ½æ˜¯æµè§ˆå™¨è¿è¡Œç¼“å­˜çš„å› ç´ ï¼Œå¹¶ä¸”å¯èƒ½çž¬é—´äº§ç”Ÿå¤šä¸ªå¹¶è¡Œæ“ä½œå ç”¨å¤§é‡cpu
var mp3Worker;
Recorder.BindDestroy("mp3Worker",function(){
	console.log("mp3Worker Destroy");
	mp3Worker&&mp3Worker.terminate();
	mp3Worker=null;
});


Recorder.prototype.mp3_envCheck=function(envInfo,set){//æ£€æŸ¥çŽ¯å¢ƒä¸‹é…ç½®æ˜¯å¦å¯ç”¨
	var errMsg="";
	//éœ€è¦å®žæ—¶ç¼–ç è¿”å›žæ•°æ®ï¼Œæ­¤æ—¶éœ€è¦æ£€æŸ¥çŽ¯å¢ƒæ˜¯å¦æœ‰å®žæ—¶ç‰¹æ€§ã€å’Œæ˜¯å¦å¯å®žæ—¶ç¼–ç 
	if(set.takeoffEncodeChunk){
		if(!envInfo.canProcess){
			errMsg=envInfo.envName+"çŽ¯å¢ƒä¸æ”¯æŒå®žæ—¶å¤„ç†";
		}else if(!newContext()){//æµè§ˆå™¨ä¸èƒ½åˆ›å»ºå®žæ—¶ç¼–ç çŽ¯å¢ƒ
			errMsg="å½“å‰æµè§ˆå™¨ç‰ˆæœ¬å¤ªä½Žï¼Œæ— æ³•å®žæ—¶å¤„ç†";
		};
	};
	return errMsg;
};
Recorder.prototype.mp3_start=function(set){//å¦‚æžœè¿”å›žnullä»£è¡¨ä¸æ”¯æŒ
	return newContext(set);
};
var openList={id:0};
var newContext=function(setOrNull){
	var worker=mp3Worker;
	try{
		if(!worker){
			var onmsg=function(e){
				var ed=e.data;
				var cur=wk_ctxs[ed.id];
				if(ed.action=="init"){
					wk_ctxs[ed.id]={
						sampleRate:ed.sampleRate
						,bitRate:ed.bitRate
						,takeoff:ed.takeoff
						
						,mp3Size:0
						,pcmSize:0
						,encArr:[]
						,encObj:new wk_lame.Mp3Encoder(1,ed.sampleRate,ed.bitRate)
					};
				}else if(!cur){
					return;
				};
				
				switch(ed.action){
				case "stop":
					cur.encObj=null;
					delete wk_ctxs[ed.id];
					break;
				case "encode":
					cur.pcmSize+=ed.pcm.length;
					var buf=cur.encObj.encodeBuffer(ed.pcm);
					if(buf.length>0){
						if(cur.takeoff){
							self.postMessage({action:"takeoff",id:ed.id,chunk:buf});
						}else{
							cur.mp3Size+=buf.buffer.byteLength;
							cur.encArr.push(buf.buffer);
						};
					};
					break;
				case "complete":
					var buf=cur.encObj.flush();
					if(buf.length>0){
						if(cur.takeoff){
							self.postMessage({action:"takeoff",id:ed.id,chunk:buf});
						}else{
							cur.mp3Size+=buf.buffer.byteLength;
							cur.encArr.push(buf.buffer);
						};
					};
					
					//åŽ»æŽ‰å¼€å¤´çš„æ ‡è®°ä¿¡æ¯å¸§
					var meta=wk_mp3TrimFix.fn(cur.encArr,cur.mp3Size,cur.pcmSize,cur.sampleRate);
					
					self.postMessage({
						action:ed.action
						,id:ed.id
						,blob:new Blob(cur.encArr,{type:"audio/mp3"})
						,meta:meta
					});
					break;
				};
			};
			
			//åˆ›å»ºä¸€ä¸ªæ–°Worker
			var jsCode=");wk_lame();var wk_ctxs={};self.onmessage="+onmsg;
			jsCode+=";var wk_mp3TrimFix={rm:"+mp3TrimFix.rm+",fn:"+mp3TrimFix.fn+"}";
			
			var lamejsCode=Recorder.lamejs.toString();
			var url=(window.URL||webkitURL).createObjectURL(new Blob(["var wk_lame=(",lamejsCode,jsCode], {type:"text/javascript"}));
			
			worker=new Worker(url);
			setTimeout(function(){
				(window.URL||webkitURL).revokeObjectURL(url);//å¿…é¡»è¦é‡Šæ”¾ï¼Œä¸ç„¶æ¯æ¬¡è°ƒç”¨å†…å­˜éƒ½æ˜Žæ˜¾æ³„éœ²å†…å­˜
			},10000);//chrome 83 fileåè®®ä¸‹å¦‚æžœç›´æŽ¥é‡Šæ”¾ï¼Œå°†ä¼šä½¿WebWorkeræ— æ³•å¯åŠ¨
			
			worker.onmessage=function(e){
				var data=e.data;
				var ctx=openList[data.id];
				if(ctx){
					if(data.action=="takeoff"){
						//å–èµ°å®žæ—¶ç”Ÿæˆçš„mp3æ•°æ®
						ctx.set.takeoffEncodeChunk(new Uint8Array(data.chunk.buffer));
					}else{
						//complete
						ctx.call&&ctx.call(data);
						ctx.call=null;
					};
				};
			};
		};
		
		var ctx={worker:worker,set:setOrNull,takeoffQueue:[]};
		if(setOrNull){
			ctx.id=++openList.id;
			openList[ctx.id]=ctx;
			
			worker.postMessage({
				action:"init"
				,id:ctx.id
				,sampleRate:setOrNull.sampleRate
				,bitRate:setOrNull.bitRate
				,takeoff:!!setOrNull.takeoffEncodeChunk
				
				,x:new Int16Array(5)//ä½Žç‰ˆæœ¬æµè§ˆå™¨ä¸æ”¯æŒåºåˆ—åŒ–TypedArray
			});
		}else{
			worker.postMessage({
				x:new Int16Array(5)//ä½Žç‰ˆæœ¬æµè§ˆå™¨ä¸æ”¯æŒåºåˆ—åŒ–TypedArray
			});
		};
		
		
		mp3Worker=worker;
		return ctx;
	}catch(e){//å‡ºé”™äº†å°±ä¸è¦æä¾›äº†
		worker&&worker.terminate();
		
		console.error(e);
		return null;
	};
};
Recorder.prototype.mp3_stop=function(startCtx){
	if(startCtx&&startCtx.worker){
		startCtx.worker.postMessage({
			action:"stop"
			,id:startCtx.id
		});
		startCtx.worker=null;
		delete openList[startCtx.id];
		
		//ç–‘ä¼¼æ³„éœ²æ£€æµ‹ æŽ’é™¤id
		var opens=-1;
		for(var k in openList){
			opens++;
		};
		if(opens){
			console.warn("mp3 workerå‰©"+opens+"ä¸ªåœ¨ä¸²è¡Œç­‰å¾…");
		};
	};
};
Recorder.prototype.mp3_encode=function(startCtx,pcm){
	if(startCtx&&startCtx.worker){
		startCtx.worker.postMessage({
			action:"encode"
			,id:startCtx.id
			,pcm:pcm
		});
	};
};
Recorder.prototype.mp3_complete=function(startCtx,True,False,autoStop){
	var This=this;
	if(startCtx&&startCtx.worker){
		startCtx.call=function(data){
			mp3TrimFixSetMeta(data.meta,startCtx.set);
			True(data.blob);
			
			if(autoStop){
				This.mp3_stop(startCtx);
			};
		};
		startCtx.worker.postMessage({
			action:"complete"
			,id:startCtx.id
		});
	}else{
		False("mp3ç¼–ç å™¨æœªæ‰“å¼€");
	};
};







//*******è¾…åŠ©å‡½æ•°************

/*è¯»å–lamejsç¼–ç å‡ºæ¥çš„mp3ä¿¡æ¯ï¼Œåªèƒ½è¯»ç‰¹å®šæ ¼å¼ï¼Œå¦‚æžœè¯»å–å¤±è´¥è¿”å›žnull
mp3Buffers=[ArrayBuffer,...]
length=mp3Buffersçš„æ•°æ®äºŒè¿›åˆ¶æ€»é•¿åº¦
*/
Recorder.mp3ReadMeta=function(mp3Buffers,length){
	//kill babel-polyfill ES6 Number.parseInt ä¸ç„¶æ”¾åˆ°Workeré‡Œé¢æ‰¾ä¸åˆ°æ–¹æ³•
	var parseInt_ES3=typeof(window)=="object"?window.parseInt:self.parseInt;
	
	var u8arr0=new Uint8Array(mp3Buffers[0]||[]);
	if(u8arr0.length<4){
		return null;
	};
	var byteAt=function(idx,u8){
		return ("0000000"+((u8||u8arr0)[idx]||0).toString(2)).substr(-8);
	};
	var b2=byteAt(0)+byteAt(1);
	var b4=byteAt(2)+byteAt(3);
	
	if(!/^1{11}/.test(b2)){//æœªå‘çŽ°å¸§åŒæ­¥
		return null;
	};
	var version=({"00":2.5,"10":2,"11":1})[b2.substr(11,2)];
	var layer=({"01":3})[b2.substr(13,2)];//ä»…æ”¯æŒLayer3
	var sampleRate=({ //lamejs -> Tables.samplerate_table
		"1":[44100, 48000, 32000]
		,"2":[22050, 24000, 16000]
		,"2.5":[11025, 12000, 8000]
	})[version];
	sampleRate&&(sampleRate=sampleRate[parseInt_ES3(b4.substr(4,2),2)]);
	var bitRate=[ //lamejs -> Tables.bitrate_table
		[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] //MPEG 2 2.5
		,[0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]//MPEG 1
	][version==1?1:0][parseInt_ES3(b4.substr(0,4),2)];
	
	if(!version || !layer || !bitRate || !sampleRate){
		return null;
	};
	
	var duration=Math.round(length*8/bitRate);
	var frame=layer==1?384:layer==2?1152:version==1?1152:576;
	var frameDurationFloat=frame/sampleRate*1000;
	var frameSize=Math.floor((frame*bitRate)/8/sampleRate*1000);
	
	//æ£€æµ‹æ˜¯å¦å­˜åœ¨Layer3å¸§å¡«å……1å­—èŠ‚ã€‚è¿™é‡ŒåªèŽ·å–ç¬¬äºŒå¸§çš„å¡«å……ä¿¡æ¯ï¼Œé¦–å¸§æ°¸è¿œæ²¡æœ‰å¡«å……ã€‚å…¶ä»–å¸§å¯èƒ½éš”ä¸€å¸§å‡ºçŽ°ä¸€ä¸ªå¡«å……ï¼Œæˆ–è€…éš”å¾ˆå¤šå¸§å‡ºçŽ°ä¸€ä¸ªå¡«å……ï¼›ç›®æµ‹æ˜¯å–å†³äºŽframeSizeæœªèˆå…¥æ—¶çš„å°æ•°éƒ¨åˆ†ï¼Œå› ä¸ºæœ‰äº›é‡‡æ ·çŽ‡çš„frameSizeä¼šå‡ºçŽ°å°æ•°ï¼ˆ11025ã€22050ã€44100 å…¸åž‹çš„é™¤ä¸å°½ï¼‰ï¼Œç„¶åŽå­—èŠ‚æ•°æ— æ³•è¡¨ç¤ºè¿™ç§å°æ•°ï¼Œå°±é€šè¿‡ä¸€å®šæ­¥é•¿æ¥å¡«å……å¼¥è¡¥å°æ•°éƒ¨åˆ†ä¸¢å¤±
	var hasPadding=0,seek=0;
	for(var i=0;i<mp3Buffers.length;i++){
		//å¯»æ‰¾ç¬¬äºŒå¸§
		var buf=mp3Buffers[i];
		seek+=buf.byteLength;
		if(seek>=frameSize+3){
			var buf8=new Uint8Array(buf);
			var idx=buf.byteLength-(seek-(frameSize+3)+1);
			var ib4=byteAt(idx,buf8);
			hasPadding=ib4.charAt(6)=="1";
			break;
		};
	};
	if(hasPadding){
		frameSize++;
	};
	
	
	return {
		version:version //1 2 2.5 -> MPEG1 MPEG2 MPEG2.5
		,layer:layer//3 -> Layer3
		,sampleRate:sampleRate //é‡‡æ ·çŽ‡ hz
		,bitRate:bitRate //æ¯”ç‰¹çŽ‡ kbps
		
		,duration:duration //éŸ³é¢‘æ—¶é•¿ ms
		,size:length //æ€»é•¿åº¦ byte
		,hasPadding:hasPadding //æ˜¯å¦å­˜åœ¨1å­—èŠ‚å¡«å……ï¼Œé¦–å¸§æ°¸è¿œæ²¡æœ‰ï¼Œè¿™ä¸ªå€¼å…¶å®žä»£è¡¨çš„ç¬¬äºŒå¸§æ˜¯å¦æœ‰å¡«å……ï¼Œå¹¶ä¸ä»£è¡¨å…¶ä»–å¸§çš„
		,frameSize:frameSize //æ¯å¸§æœ€å¤§é•¿åº¦ï¼Œå«å¯èƒ½å­˜åœ¨çš„1å­—èŠ‚padding byte
		,frameDurationFloat:frameDurationFloat //æ¯å¸§æ—¶é•¿ï¼Œå«å°æ•° ms
	};
};

//åŽ»æŽ‰lamejså¼€å¤´çš„æ ‡è®°ä¿¡æ¯å¸§ï¼Œå…å¾—mp3è§£ç å‡ºæ¥çš„æ—¶é•¿æ¯”pcmçš„é•¿å¤ªå¤š
var mp3TrimFix={//minfiy keep name
rm:Recorder.mp3ReadMeta
,fn:function(mp3Buffers,length,pcmLength,pcmSampleRate){
	var meta=this.rm(mp3Buffers,length);
	if(!meta){
		return {err:"mp3éžé¢„å®šæ ¼å¼"};
	};
	var pcmDuration=Math.round(pcmLength/pcmSampleRate*1000);
	
	//å¼€å¤´å¤šå‡ºè¿™ä¹ˆå¤šå¸§ï¼Œç§»é™¤æŽ‰ï¼›æ­£å¸¸æƒ…å†µä¸‹æœ€å¤šä¸º2å¸§
	var num=Math.floor((meta.duration-pcmDuration)/meta.frameDurationFloat);
	if(num>0){
		var size=num*meta.frameSize-(meta.hasPadding?1:0);//é¦–å¸§æ²¡æœ‰å¡«å……ï¼Œç¬¬äºŒå¸§å¯èƒ½æœ‰å¡«å……ï¼Œè¿™é‡Œå‡è®¾æœ€å¤šä¸º2å¸§ï¼ˆæµ‹è¯•å¹¶æœªå‡ºçŽ°3å¸§ä»¥ä¸Šæƒ…å†µï¼‰ï¼Œå…¶ä»–å¸§ä¸ç®¡ï¼Œå°±ç®—å‡ºçŽ°äº†å¹¶ä¸”å¯¼è‡´äº†é”™è¯¯åŽé¢è‡ªåŠ¨å®¹é”™
		length-=size;
		var arr0=0,arrs=[];
		for(var i=0;i<mp3Buffers.length;i++){
			var arr=mp3Buffers[i];
			if(size<=0){
				break;
			};
			if(size>=arr.byteLength){
				size-=arr.byteLength;
				arrs.push(arr);
				mp3Buffers.splice(i,1);
				i--;
			}else{
				mp3Buffers[i]=arr.slice(size);
				arr0=arr;
				size=0;
			};
		};
		var checkMeta=this.rm(mp3Buffers,length);
		if(!checkMeta){
			//è¿˜åŽŸå˜æ›´ï¼Œåº”è¯¥ä¸å¤ªå¯èƒ½ä¼šå‡ºçŽ°
			arr0&&(mp3Buffers[0]=arr0);
			for(var i=0;i<arrs.length;i++){
				mp3Buffers.splice(i,0,arrs[i]);
			};
			meta.err="fixåŽæ•°æ®é”™è¯¯ï¼Œå·²è¿˜åŽŸï¼Œé”™è¯¯åŽŸå› ä¸æ˜Ž";
		};
		
		var fix=meta.trimFix={};
		fix.remove=num;
		fix.removeDuration=Math.round(num*meta.frameDurationFloat);
		fix.duration=Math.round(length*8/meta.bitRate);
	};
	return meta;
}
};
var mp3TrimFixSetMeta=function(meta,set){
	var tag="MP3ä¿¡æ¯ ";
	if(meta.sampleRate&&meta.sampleRate!=set.sampleRate || meta.bitRate&&meta.bitRate!=set.bitRate){
		console.warn(tag+"å’Œè®¾ç½®çš„ä¸åŒ¹é…set:"+set.bitRate+"kbps "+set.sampleRate+"hzï¼Œå·²æ›´æ–°set:"+meta.bitRate+"kbps "+meta.sampleRate+"hz",set);
		set.sampleRate=meta.sampleRate;
		set.bitRate=meta.bitRate;
	};
	
	var trimFix=meta.trimFix;
	if(trimFix){
		tag+="Fixç§»é™¤"+trimFix.remove+"å¸§"+trimFix.removeDuration+"ms -> "+trimFix.duration+"ms";
		if(trimFix.remove>2){
			meta.err=(meta.err?meta.err+", ":"")+"ç§»é™¤å¸§æ•°è¿‡å¤š";
		};
	}else{
		tag+=(meta.duration||"-")+"ms";
	};
	
	if(meta.err){
		console.error(tag,meta.err,meta);
	}else{
		console.log(tag,meta);
	};
};


	
})();